﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace DotConsulting.VisualStudio.BuildOutputCopy
{
    public class AsyncDelegateCommand : ICommand, IDisposable
    {

        BackgroundWorker _worker = new BackgroundWorker();
        Func<bool> _canExecute;

        public AsyncDelegateCommand(Action<object> action,
            Func<bool> canExecute = null,
            Action<object> completed = null,
            Action<Exception> error = null)
        {
            GC.SuppressFinalize(this);

            _worker.DoWork += (s, e) =>
                {
                    CommandManager.InvalidateRequerySuggested();
                    action(e.Argument);
                };

            _worker.RunWorkerCompleted += (s, e) =>
                {
                    if (completed != null && e.Error == null)
                    {
                        completed(e.Result);
                    }

                    if (error != null && e.Error != null)
                    {
                        error(e.Error);
                    }

                    CommandManager.InvalidateRequerySuggested();
                };

            _canExecute = canExecute;
        }

        public void Cancel()
        {
            if (_worker.IsBusy)
            {
                _worker.CancelAsync();
            }
        }

        public bool CanExecute(object parameter)
        {
            return (_canExecute == null) ?
                !(_worker.IsBusy) : !(_worker.IsBusy)
                && _canExecute();
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            _worker.RunWorkerAsync(parameter);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_worker != null)
                {
                    _worker.Dispose();
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
    }
}
